home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / infosrvr / dev / scott / WWW / NextStep / Implementation / old / HTFTP.c < prev    next >
C/C++ Source or Header  |  1991-09-04  |  21KB  |  790 lines

  1. /*            File Transfer Protocol (FTP) Client
  2. **            for a WorldWideWeb browser
  3. **            ===================================
  4. **
  5. **    A cache of control connections is kept.
  6. **
  7. ** Note: Port allocation
  8. **
  9. **    It is essential that the port is allocated by the system, rather
  10. **    than chosen in rotation by us (POLL_PORTS), or the following
  11. **    problem occurs.
  12. **
  13. **    It seems that an attempt by the server to connect to a port which has
  14. **    been used recently by a listen on the same socket, or by another
  15. **    socket this or another process causes a hangup of (almost exactly)
  16. **    one minute. Therefore, we have to use a rotating port number.
  17. **    The problem remians that if the application is run twice in quick
  18. **    succession, it will hang for what remains of a minute.
  19. **
  20. ** History:
  21. **     2 May 91    Written TBL, as a part of the WorldWideWeb project.
  22. **
  23. ** Options:
  24. **    LISTEN        We listen, the other guy connects for data.
  25. **            Otherwise, other way round, but problem finding our
  26. **            internet address!
  27. */
  28.  
  29. #define LISTEN        /* @@@@ Test */
  30.  
  31. /*
  32. BUGS:    @@@      Limit connection cache size!
  33.         400 errors should cause drop connection.
  34.         Error reporting to user.
  35.         400 & 500 errors are acked by user with windows.
  36.         Use configuration file for user names
  37.         Prompt user for password
  38.         
  39. **        Note for portablility this version does not use select() and
  40. **        so does not watch the control and data channels at the
  41. **        same time.
  42. */        
  43.  
  44. #define REPEAT_PORT    /* Give the port number for each file */
  45. #define REPEAT_LISTEN    /* Close each listen socket and open a new one */
  46.  
  47. #ifndef IPPORT_FTP
  48. #define IPPORT_FTP    21
  49. #endif
  50. /* define POLL_PORTS         If allocation does not work, poll ourselves.*/
  51. #define LISTEN_BACKLOG 2    /* Number of pending connect requests (TCP)*/
  52.  
  53. #define FIRST_TCP_PORT    1024    /* Region to try for a listening port */
  54. #define LAST_TCP_PORT    5999    
  55.  
  56. #define LINE_LENGTH 256
  57. #define COMMAND_LENGTH 256
  58.  
  59. #include "HTParse.h"
  60. #include "HTUtils.h"
  61. #include "tcp.h"
  62. #include "HTTCP.h"
  63.  
  64. #ifdef REMOVED_CODE
  65. extern char *malloc();
  66. extern void free();
  67. extern char *strncpy();
  68. #endif
  69.  
  70. typedef struct _connection {
  71.     struct _connection *    next;    /* Link on list     */
  72.     u_long            addr;    /* IP address        */
  73.     int                socket;    /* Socket number for communication */
  74. } connection;
  75.  
  76. #ifndef NIL
  77. #define NIL 0
  78. #endif
  79.  
  80.  
  81. /*    Module-Wide Variables
  82. **    ---------------------
  83. */
  84. PRIVATE connection * connections =0;    /* Linked list of connections */
  85. PRIVATE char    response_text[LINE_LENGTH+1];/* Last response from NewsHost */
  86. PRIVATE connection * control;        /* Current connection */
  87. PRIVATE int    data_soc;        /* Socket for data transfer */
  88.  
  89. #ifdef POLL_PORTS
  90. PRIVATE    unsigned short    port_number = FIRST_TCP_PORT;
  91. #endif
  92.  
  93. #ifdef LISTEN
  94. PRIVATE int     master_socket = -1;    /* Listening socket = invalid    */
  95. PRIVATE char    port_command[255];    /* Command for setting the port */
  96. PRIVATE fd_set    open_sockets;         /* Mask of active channels */
  97. PRIVATE int    num_sockets;          /* Number of sockets to scan */
  98. #else
  99. PRIVATE    unsigned short    passive_port;    /* Port server specified for data */
  100. #endif
  101.  
  102.  
  103. #define INPUT_BUFFER_SIZE 4096
  104. PRIVATE char input_buffer[INPUT_BUFFER_SIZE];        /* Input buffer */
  105. PRIVATE char * input_read_pointer;
  106. PRIVATE char * input_write_pointer;
  107. #define NEXT_CHAR next_char()
  108.  
  109.  
  110.  
  111. /*    Procedure: Read a character from the control connection
  112. **    -------------------------------------------------------
  113. */
  114. #ifdef __STDC__
  115. PRIVATE char next_char(void)
  116. #else
  117. PRIVATE char next_char()
  118. #endif
  119. {
  120.     int status;
  121.     if (input_read_pointer >= input_write_pointer) {
  122.     status = NETREAD(control->socket, input_buffer, INPUT_BUFFER_SIZE);    /*  Get some more data */
  123.     if (status <= 0) return (char)-1;
  124.     input_write_pointer = input_buffer + status;
  125.     input_read_pointer = input_buffer;
  126.     }
  127. #ifdef NOT_ASCII
  128.     {
  129.         char c = *input_read_pointer++;
  130.     return FROMASCII(c);
  131.     }
  132. #else
  133.     return *input_read_pointer++;
  134. #endif
  135. }
  136.  
  137.  
  138. /*    Execute Command and get Response
  139. **    --------------------------------
  140. **
  141. **    See the state machine illustrated in RFC959, p57. This implements
  142. **    one command/reply sequence.  It also interprets lines which are to
  143. **    be continued, which are marked with a "-" immediately after the
  144. **    status code.
  145. **
  146. ** On entry,
  147. **    con    points to the connection which is established.
  148. **    cmd    points to a command, or is NIL to just get the response.
  149. **
  150. **    The command is terminated with the CRLF pair.
  151. **
  152. ** On exit,
  153. **    returns:  The first digit of the reply type,
  154. **          or negative for failure.
  155. */
  156. #ifdef __STDC__
  157. PRIVATE int response(char * cmd)
  158. #else
  159. PRIVATE int response(cmd)
  160.     char * cmd;
  161. #endif
  162. {
  163.     int result;                /* Three-digit decimal code */
  164.     char    continuation;
  165.     int status;
  166.     if (cmd) {
  167.     
  168.     if (TRACE) printf("  Tx: %s", cmd);
  169.  
  170. #ifdef NOT_ASCII
  171.     {
  172.         char * p;
  173.         for(p=cmd; *p; p++) {
  174.             *p = TOASCII(*p);
  175.         }
  176.     }
  177. #endif 
  178.     status = NETWRITE(control->socket, cmd, strlen(cmd));
  179.     if (status<0) {
  180.         if (TRACE) printf("FTP: Error %d sending command",
  181.         status);
  182.         return status;
  183.     }
  184.     }
  185.  
  186.     do {
  187.     char *p = response_text;
  188.     for(;;) {  
  189.         if (((*p++=NEXT_CHAR) == '\n')
  190.             || (p == &response_text[LINE_LENGTH])) {
  191.         *p++=0;            /* Terminate the string */
  192.         if (TRACE) printf("    Rx: %s", response_text);
  193.         sscanf(response_text, "%d%c", &result, &continuation);
  194.         break;        
  195.         } /* if end of line */
  196.         
  197.         if (*(p-1) < 0) return -1;    /* End of file on response */
  198.         
  199.     } /* Loop over characters */
  200.  
  201.     } while (continuation == '-');
  202.     
  203.     return result/100;
  204. }
  205.  
  206.  
  207. /*    Close an individual connection
  208. **
  209. */
  210. #ifdef TEST        /* use later when cache is limited! */
  211. #ifdef __STDC__
  212. PRIVATE int close_connection(connection * con)
  213. #else
  214. PRIVATE int close_connection(con)
  215.     connection *con;
  216. #endif
  217. {
  218.     connection * scan;
  219.     int status = NETCLOSE(con->socket);
  220.     if (TRACE) printf("FTP: Closing control socket %d\n", con->socket);
  221.     if (connections==con) {
  222.         connections = con->next;
  223.     return status;
  224.     }
  225.     for(scan=connections; scan; scan=scan->next) {
  226.         if (scan->next == con) {
  227.         scan->next = con->next;    /* Unlink */
  228.         return status;
  229.     } /*if */
  230.     } /* for */
  231.     return -1;        /* very strange -- was not on list. */
  232. }
  233. #endif /* TEST */
  234.  
  235. /*    Get a valid connection to the host
  236. **    ----------------------------------
  237. **
  238. ** On entry,
  239. **    arg    points to the name of the host in a hypertext address
  240. ** On exit,
  241. **    returns    <0 if error
  242. **        socket number if success
  243. **
  244. **    This routine takes care of managing timed-out connections, and
  245. **    limiting the number of connections in use at any one time.
  246. **
  247. **    It ensures that all connections are logged in if they exist.
  248. **    It ensures they have the port number transferred.
  249. */
  250. #ifdef __STDC__
  251. PRIVATE int get_connection(const char * arg)
  252. #else
  253. PRIVATE int get_connection(arg)
  254.     char * arg;
  255. #endif
  256.  
  257. {
  258.     struct hostent * phost;        /* Pointer to host -- See netdb.h */
  259.     struct sockaddr_in soc_address;    /* Binary network address */
  260.     struct sockaddr_in* sin = &soc_address;
  261.     if (!arg) return -1;        /* Bad if no name sepcified    */
  262.     if (!*arg) return -1;        /* Bad if name had zero length    */
  263.  
  264. /*  Set up defaults:
  265. */
  266.     sin->sin_family = AF_INET;                /* Family, host order  */
  267.     sin->sin_port = htons(IPPORT_FTP);            /* Well Known Number    */
  268.  
  269.     if (TRACE) printf("FTP: Looking for %s\n", arg);
  270.  
  271. /* Get node name:
  272. */
  273.     {
  274.     char *p1 = HTParse(arg, "", PARSE_HOST);
  275.     
  276.     if (*p1>='0' && *p1<='9') {   /* Numeric node address: */
  277.         sin->sin_addr.s_addr = inet_addr(p1); /* See arpa/inet.h */
  278.  
  279.     } else {            /* Alphanumeric node name: */
  280.         phost=gethostbyname(p1);    /* See netdb.h */
  281.         if (!phost) {
  282.         if (TRACE) printf(
  283.             "FTP: Can't find internet node name `%s'.\n",
  284.             p1);
  285.         return -3;  /* Fail? */
  286.         }
  287.         memcpy(&sin->sin_addr, phost->h_addr, phost->h_length);
  288.     }
  289.  
  290.     if (TRACE) printf( 
  291.         "FTP: Parsed remote address as port %d, inet %d.%d.%d.%d\n",
  292.             (unsigned int)ntohs(sin->sin_port),
  293.             (int)*((unsigned char *)(&sin->sin_addr)+0),
  294.             (int)*((unsigned char *)(&sin->sin_addr)+1),
  295.             (int)*((unsigned char *)(&sin->sin_addr)+2),
  296.             (int)*((unsigned char *)(&sin->sin_addr)+3));
  297.         free(p1);
  298.     } /* scope of p1 */
  299.  
  300.     input_read_pointer = input_write_pointer = input_buffer;
  301.     
  302. /*    Now we check whether we already have a connection to that port.
  303. */
  304.  
  305.     {
  306.     connection * scan;
  307.     for (scan=connections; scan; scan=scan->next) {
  308.         if (sin->sin_addr.s_addr == scan->addr) {
  309.           if (TRACE) printf(
  310.         "FTP: Already have connection for %d.%d.%d.%d.\n",
  311.             (int)*((unsigned char *)(&scan->addr)+0),
  312.             (int)*((unsigned char *)(&scan->addr)+1),
  313.             (int)*((unsigned char *)(&scan->addr)+2),
  314.             (int)*((unsigned char *)(&scan->addr)+3));
  315.         return scan->socket;        /* Good return */
  316.         } else {
  317.           if (TRACE) printf(
  318.         "FTP: Existing connection is %d.%d.%d.%d\n",
  319.             (int)*((unsigned char *)(&scan->addr)+0),
  320.             (int)*((unsigned char *)(&scan->addr)+1),
  321.             (int)*((unsigned char *)(&scan->addr)+2),
  322.             (int)*((unsigned char *)(&scan->addr)+3));
  323.         }
  324.     }
  325.     }
  326.  
  327.    
  328. /*    Now, let's get a socket set up from the server:
  329. */      
  330.     {
  331.         int status;
  332.     connection * con = (connection *)malloc(sizeof(*con));
  333.     con->addr = sin->sin_addr.s_addr;    /* save it */
  334.     status = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  335.     if (status<0) {
  336.         (void) HTInetStatus("socket");
  337.         free(con);
  338.         return status;
  339.     }
  340.     con->socket = status;
  341.  
  342.         status = connect(con->socket, (struct sockaddr*)&soc_address,
  343.      sizeof(soc_address));
  344.         if (status<0){
  345.         (void) HTInetStatus("connect");
  346.         if (TRACE) printf(
  347.             "FTP: Unable to connect to remote host for `%s'.\n",
  348.             arg);
  349.         NETCLOSE(con->socket);
  350.         free(con);
  351.         return status;            /* Bad return */
  352.     }
  353.     
  354.     if (TRACE) printf("FTP connected, socket %d\n", con->socket);
  355.     control = con;            /* Current control connection */
  356.  
  357.  
  358. /*    Now we log in        @@@ Look up username, prompt for pw.
  359. */
  360.     {
  361.         int status = response(NIL);    /* Get greeting */
  362.         if (status == 2) status = response("USER anonymous\r\n");
  363.         if (status == 3) {
  364.             char * command = (char*)malloc(10+strlen(HTHostName())+2+1);
  365.         sprintf(command, "PASS user@%s\r\n", HTHostName()); /*@@*/
  366.             status = response(command);
  367.         free(command);
  368.         }
  369.         if (status == 3) status = response("ACCT noaccount\r\n");
  370.         if (status !=2) {
  371.             if (TRACE) printf("FTP: Login fail: %s", response_text);
  372.             NETCLOSE(con->socket);
  373.         free(con);
  374.             return -status;        /* Bad return */
  375.         }
  376.         if (TRACE) printf("FTP: Logged in.\n");
  377.     }
  378.  
  379. /*    Now we inform the server of the port number we will listen on
  380. */
  381. #ifndef REPEAT_PORT
  382.     {
  383.         int status = response(port_command);
  384.         if (status !=2) {
  385.             NETCLOSE(con->socket);
  386.         free(con);
  387.             return -status;        /* Bad return */
  388.         }
  389.         if (TRACE) printf("FTP: Port defined.\n");
  390.     }
  391. #endif
  392.     con->next = connections;    /* Link onto list of good ones */
  393.     connections = con;
  394.     return con->socket;            /* Good return */
  395.     } /* Scope of con */
  396. }
  397.  
  398.  
  399. #ifdef LISTEN
  400.  
  401. /*    Close Master (listening) socket
  402. **    -------------------------------
  403. **
  404. **
  405. */
  406. #ifdef __STDC__
  407. PRIVATE int close_master_socket(void)
  408. #else
  409. PRIVATE int close_master_socket()
  410. #endif
  411. {
  412.     int status;
  413.     FD_CLR(master_socket, &open_sockets);
  414.     status = close(master_socket);
  415.     if (TRACE) printf("FTP: Closed master socket %d\n", master_socket);
  416.     master_socket = -1;
  417.     if (status<0) return HTInetStatus("close master socket");
  418.     else return status;
  419. }
  420.  
  421.  
  422. /*    Open a master socket for listening on
  423. **    -------------------------------------
  424. **
  425. **    When data is transferred, we open a port, and wait for the server to
  426. **    connect with the data.
  427. **
  428. ** On entry,
  429. **    master_socket    Must be negative if not set up already.
  430. ** On exit,
  431. **    Returns        socket number if good
  432. **            less than zero if error.
  433. **    master_socket    is socket number if good, else negative.
  434. **    port_number    is valid if good.
  435. */
  436. #ifdef __STDC__
  437. PRIVATE int get_listen_socket(void)
  438. #else
  439. PRIVATE int get_listen_socket()
  440. #endif
  441. {
  442.     struct sockaddr_in soc_address;    /* Binary network address */
  443.     struct sockaddr_in* sin = &soc_address;
  444.     int new_socket;            /* Will be master_socket */
  445.     
  446.     
  447.     FD_ZERO(&open_sockets);    /* Clear our record of open sockets */
  448.     num_sockets = 0;
  449.     
  450. #ifndef REPEAT_LISTEN
  451.     if (master_socket>=0) return master_socket;  /* Done already */
  452. #endif
  453.  
  454. /*  Create internet socket
  455. */
  456.     new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  457.     
  458.     if (new_socket<0)
  459.     return HTInetStatus("socket for master socket");
  460.     
  461.     if (TRACE) printf("FTP: Opened master socket number %d\n", new_socket);
  462.     
  463. /*  Search for a free port.
  464. */
  465.     sin->sin_family = AF_INET;        /* Family = internet, host order  */
  466.     sin->sin_addr.s_addr = INADDR_ANY; /* Any peer address */
  467. #ifdef POLL_PORTS
  468.     {
  469.         unsigned short old_port_number = port_number;
  470.     for(port_number=old_port_number+1;;port_number++){ 
  471.         int status;
  472.         if (port_number > LAST_TCP_PORT)
  473.         port_number = FIRST_TCP_PORT;
  474.         if (port_number == old_port_number) {
  475.         return HTInetStatus("bind");
  476.         }
  477.         soc_address.sin_port = htons(port_number);
  478.         if ((status=bind(new_socket,
  479.             (struct sockaddr*)&soc_address,
  480.                 /* Cast to generic sockaddr */
  481.             sizeof(soc_address))) == 0)
  482.         break;
  483.         if (TRACE) printf(
  484.             "TCP bind attempt to port %d yields %d, errno=%d\n",
  485.         port_number, status, errno);
  486.     } /* for */
  487.     }
  488. #else
  489.     {
  490.         int status;
  491.     int address_length = sizeof(soc_address);
  492.     status = getsockname(control->socket,
  493.             (struct sockaddr *)&soc_address,
  494.              &address_length);
  495.     if (status<0) return HTInetStatus("getsockname");
  496.     CTRACE(tfp, "FTP: This host is %s\n",
  497.         HTInetString(sin));
  498.     
  499.     soc_address.sin_port = 0;    /* Unspecified: please allocate */
  500.     status=bind(new_socket,
  501.         (struct sockaddr*)&soc_address,
  502.             /* Cast to generic sockaddr */
  503.         sizeof(soc_address));
  504.     if (status<0) return HTInetStatus("bind");
  505.     
  506.     address_length = sizeof(soc_address);
  507.     status = getsockname(new_socket,
  508.             (struct sockaddr*)&soc_address,
  509.             &address_length);
  510.     if (status<0) return HTInetStatus("getsockname");
  511.     }
  512. #endif    
  513.  
  514.     CTRACE(tfp, "FTP: bound to port %d on %s\n",
  515.         (unsigned int)ntohs(sin->sin_port),
  516.     HTInetString(sin));
  517.  
  518. #ifdef REPEAT_LISTEN
  519.     if (master_socket>=0)
  520.         (void) close_master_socket();
  521. #endif    
  522.     
  523.     master_socket = new_socket;
  524.     
  525. /*    Now we must find out who we are to tell the other guy
  526. */
  527.     (void)HTHostName();     /* Make address valid - doesn't work*/
  528. /*   memcpy(&sin->sin_addr, &HTHostAddress.sin_addr, sizeof(sin->sin_addr)); */
  529.     sprintf(port_command, "PORT %d,%d,%d,%d,%d,%d\r\n",
  530.             (int)*((unsigned char *)(&sin->sin_addr)+0),
  531.             (int)*((unsigned char *)(&sin->sin_addr)+1),
  532.             (int)*((unsigned char *)(&sin->sin_addr)+2),
  533.             (int)*((unsigned char *)(&sin->sin_addr)+3),
  534.             (int)*((unsigned char *)(&sin->sin_port)+0),
  535.             (int)*((unsigned char *)(&sin->sin_port)+1));
  536.  
  537.  
  538. /*    Inform TCP that we will accept connections
  539. */
  540.     if (listen(master_socket, 1)<0) {
  541.     master_socket = -1;
  542.     return HTInetStatus("listen");
  543.     }
  544.     CTRACE(tfp, "TCP: Master socket(), bind() and listen() all OK\n");
  545.     FD_SET(master_socket, &open_sockets);
  546.     if ((master_socket+1) > num_sockets) num_sockets=master_socket+1;
  547.  
  548.     return master_socket;        /* Good */
  549.  
  550. } /* get_listen_socket */
  551. #endif
  552.  
  553.  
  554. /*    Retrieve File from Server
  555. **    -------------------------
  556. **
  557. ** On entry,
  558. **    name        WWW address of a file: document, including hostname
  559. ** On exit,
  560. **    returns        Socket number for file if good.
  561. **            <0 if bad.
  562. */
  563. #ifdef __STDC__
  564. PUBLIC int HTFTP_open_file_read(CONST char * name)
  565. #else
  566. PUBLIC int HTFTP_open_file_read(name)
  567.     char * name;
  568. #endif
  569. {
  570.     int status = get_connection(name);
  571.     if (status<0) return status;
  572.  
  573. #ifdef LISTEN
  574.     status = get_listen_socket();
  575.     if (status<0) return status;
  576.     
  577. #ifdef REPEAT_PORT
  578. /*    Inform the server of the port number we will listen on
  579. */
  580.     {
  581.     int status = response(port_command);
  582.     if (status !=2) {
  583.         return -status;        /* Bad return */
  584.     }
  585.     if (TRACE) printf("FTP: Port defined.\n");
  586.     }
  587. #endif
  588. #else    /* Use PASV */
  589. /*    Tell the server to be passive
  590. */
  591.     {
  592.     int status = response("PASV\r\n");
  593.     char *p;
  594.     int reply, h0, h1, h2, h3, p0, p1;    /* Parts of reply */
  595.     if (status !=2) {
  596.         return -status;        /* Bad return */
  597.     }
  598.     for(p=response_text; *p; p++)
  599.         if ((*p<'0')||(*p>'9')) *p = ' ';    /* Keep only digits */
  600.     status = sscanf(response_text, "%d%d%d%d%d%d%d",
  601.         &reply, &h0, &h1, &h2, &h3, &p0, &p1);
  602.     if (status<5) {
  603.         if (TRACE) printf("FTP: PASV reply has no inet address!\n");
  604.         return -99;
  605.     }
  606.     passive_port = (p0<<8) + p1;
  607.     if (TRACE) printf("FTP: Server is listening on port %d\n",
  608.         passive_port);
  609.     }
  610.  
  611. /*    Open connection for data:
  612. */
  613.     {
  614.     struct sockaddr_in soc_address;
  615.     int status = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  616.     if (status<0) {
  617.         (void) HTInetStatus("socket for data socket");
  618.         return status;
  619.     }
  620.     data_soc = status;
  621.     
  622.     soc_address.sin_addr.s_addr = control->addr;
  623.     soc_address.sin_port = htons(passive_port);
  624.         soc_address.sin_family = AF_INET;        /* Family, host order  */
  625.     if (TRACE) printf( 
  626.         "FTP: Data remote address is port %d, inet %d.%d.%d.%d\n",
  627.             (unsigned int)ntohs(soc_address.sin_port),
  628.             (int)*((unsigned char *)(&soc_address.sin_addr)+0),
  629.             (int)*((unsigned char *)(&soc_address.sin_addr)+1),
  630.             (int)*((unsigned char *)(&soc_address.sin_addr)+2),
  631.             (int)*((unsigned char *)(&soc_address.sin_addr)+3));
  632.  
  633.         status = connect(data_soc, (struct sockaddr*)&soc_address,
  634.          sizeof(soc_address));
  635.         if (status<0){
  636.         (void) HTInetStatus("connect for data");
  637.         NETCLOSE(data_soc);
  638.         return status;            /* Bad return */
  639.     }
  640.     
  641.     if (TRACE) printf("FTP data connected, socket %d\n", data_soc);
  642.     }
  643. #endif /* use PASV */
  644.  
  645. /*    Ask for the file:
  646. */    
  647.     {
  648.         char *filename = HTParse(name, "", PARSE_PATH + PARSE_PUNCTUATION);
  649.     char command[LINE_LENGTH+1];
  650.     sprintf(command, "RETR %s\r\n", filename);
  651.     status = response(command);
  652.     free(filename);
  653.     
  654.     if (status!=1) return -status;        /* Action not started */
  655.     }
  656.  
  657. #ifdef LISTEN
  658. /*    Wait for the connection
  659. */    
  660.     {
  661.     struct sockaddr_in soc_address;
  662.         int    soc_addrlen=sizeof(soc_address);
  663.     status = accept(master_socket,
  664.             (struct sockaddr *)&soc_address,
  665.             &soc_addrlen);
  666.     if (status<0)
  667.         return HTInetStatus("accept");
  668.     CTRACE(tfp, "TCP: Accepted new socket %d\n", status);
  669.     data_soc = status;
  670.     }
  671. #else
  672. #endif
  673.     return data_soc;
  674.        
  675. } /* open_file_read */
  676.  
  677. /*    Close socket opened for reading a file, and get final message
  678. **    -------------------------------------------------------------
  679. **
  680. */
  681. #ifdef __STDC__
  682. PUBLIC int HTFTP_close_file(int soc)
  683. #else
  684. PUBLIC int HTFTP_close_file(soc)
  685.     int soc;
  686. #endif
  687. {
  688.     int status;
  689.  
  690.     if (soc!=data_soc) {
  691.         if (TRACE) printf("HTFTP: close socket %d: (not FTP data socket).\n",
  692.         soc);
  693.     return NETCLOSE(soc);
  694.     }
  695.     status = NETCLOSE(data_soc);
  696.     if (TRACE) printf("FTP: Closing data socket %d\n", data_soc);
  697.     if (status<0) (void) HTInetStatus("close");    /* Comment only */
  698.     
  699.     status = response(NIL);
  700.     if (status!=2) return -status;
  701.     
  702.     data_soc = -1;    /* invalidate it */
  703.     return status;     /* Good */
  704. }
  705.  
  706.  
  707. /*___________________________________________________________________________
  708. */
  709. /*    Test program only
  710. **    -----------------
  711. **
  712. **    Compiling this with -DTEST produces a test program.
  713. **
  714. ** Syntax:
  715. **    test <file or option> ...
  716. **
  717. **    options:    -v    Verbose: Turn trace on at this point
  718. */
  719. #ifdef TEST
  720.  
  721. PUBLIC int WWW_TraceFlag;
  722.  
  723. #ifdef __STDC__
  724. int main(int argc, char*argv[])
  725. #else
  726. int main(argc, argv)
  727.     int argc;
  728.     char *argv[];
  729. #endif
  730. {
  731.     
  732.     int arg;            /* Argument number */
  733.     int status;
  734.     connection * con;
  735.     WWW_TraceFlag = (0==strcmp(argv[1], "-v"));    /* diagnostics ? */
  736.  
  737. #ifdef SUPRESS    
  738.     status = get_listen_socket();
  739.     if (TRACE) printf("get_listen_socket returns %d\n\n", status);
  740.     if (status<0) exit(status);
  741.  
  742.     status = get_connection(argv[1]);    /* test double use */
  743.     if (TRACE) printf("get_connection(`%s') returned %d\n\n", argv[1], status);
  744.     if (status<0) exit(status);
  745. #endif
  746.  
  747.     for(arg=1; arg<argc; arg++) {        /* For each argument */
  748.          if (0==strcmp(argv[arg], "-v")) {
  749.              WWW_TraceFlag = 1;            /* -v => Trace on */
  750.  
  751.      } else {                /* Filename: */
  752.     
  753.         status = HTTP_open_file_read(argv[arg]);
  754.         if (TRACE) printf("open_file_read returned %d\n\n", status);
  755.         if (status<0) exit(status);
  756.         
  757.     /*    Copy the file to std out:
  758.     */   
  759.         {
  760.         char buffer[INPUT_BUFFER_SIZE];
  761.         for(;;) {
  762.             int status = NETREAD(data_soc, buffer, INPUT_BUFFER_SIZE);
  763.             if (status<=0) {
  764.             if (status<0) (void) HTInetStatus("read");
  765.             break;
  766.             }
  767.             status = write(1, buffer, status);
  768.             if (status<0) {
  769.             printf("Write failure!\n");
  770.             break;
  771.             }
  772.         }
  773.         }
  774.     
  775.         status = HTTP_close_file(data_soc);
  776.         if (TRACE) printf("Close_file returned %d\n\n", status);
  777.  
  778.         } /* if */
  779.     } /* for */
  780.     status = response("QUIT\r\n");        /* Be good */
  781.     if (TRACE) printf("Quit returned %d\n", status);
  782.  
  783.     while(connections) close_connection(connections);
  784.     
  785.     close_master_socket();
  786.          
  787. } /* main */
  788. #endif  /* TEST */
  789.  
  790.